package com.lwlean.test.utils.excel;

import com.lwlean.test.utils.excel.handle.ExcelHeader;
import com.lwlean.test.utils.excel.handle.ExcelTemplate;
import com.lwlean.test.utils.excel.util.Utils;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.poi.ss.usermodel.*;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Created by lean on 2017/6/20.
 */
public class ExcelHelper {

    static private ExcelHelper excelUtils = new ExcelHelper();

    private ExcelHelper() {
    }

    public static ExcelHelper getInstance() {
        return excelUtils;
    }

    public <T> List<T> readExcel2Objects(InputStream is, Class<T> clazz, int offsetLine, int limitLine, int
            sheetIndex) throws Exception {
        Workbook workbook = WorkbookFactory.create(is);
        return readExcel2ObjectsHandler(workbook, clazz, offsetLine, limitLine, sheetIndex);
    }

    public <T> List<T> readExcel2Objects(InputStream is, Class<T> clazz)
            throws Exception {
        return readExcel2Objects(is, clazz, 0, Integer.MAX_VALUE, 0);
    }

    private <T> List<T> readExcel2ObjectsHandler(Workbook workbook, Class<T> clazz, int offsetLine, int limitLine,
                                                 int sheetIndex) throws Exception {
        Sheet sheet = workbook.getSheetAt(sheetIndex);
        Row row = sheet.getRow(offsetLine);
        List<T> list = new ArrayList<T>();
        Map<Integer, ExcelHeader> maps = Utils.getHeaderMap(row, clazz);
        if (maps == null || maps.size() <= 0)
            throw new RuntimeException("要读取的Excel的格式不正确，检查是否设定了合适的行");
        int maxLine = sheet.getLastRowNum() > (offsetLine + limitLine) ? (offsetLine + limitLine) : sheet
                .getLastRowNum();
        for (int i = offsetLine + 1; i <= maxLine; i++) {
            row = sheet.getRow(i);
            T obj = clazz.newInstance();
            for (Cell cell : row) {
                int ci = cell.getColumnIndex();
                ExcelHeader header = maps.get(ci);
                if (null == header)
                    continue;
                String filed = header.getFiled();
                String val = Utils.getCellValue(cell);
                Object value = Utils.str2TargetClass(val, header.getFiledClazz());
                BeanUtils.copyProperty(obj, filed, value);
            }
            list.add(obj);
        }
        return list;
    }

    /**
     * 导出
     * @param templatePath
     * @param sheetIndex
     * @param data
     * @param extendMap
     * @param clazz
     * @param isWriteHeader
     * @param targetPath
     * @throws Exception
     */

    public void exportObjects2Excel(String templatePath, int sheetIndex, List<?> data, Map<String, String> extendMap,
                                    Class clazz, boolean isWriteHeader, String targetPath) throws Exception {

        exportExcelByModuleHandler(templatePath, sheetIndex, data, extendMap, clazz, isWriteHeader)
                .write2File(targetPath);
    }

    public void exportObjects2Excel(String templatePath, int sheetIndex, List<?> data, Map<String, String> extendMap,
                                    Class clazz, boolean isWriteHeader, OutputStream os) throws Exception {

        exportExcelByModuleHandler(templatePath, sheetIndex, data, extendMap, clazz, isWriteHeader)
                .write2Stream(os);
    }

    public void exportObjects2Excel(String templatePath, List<?> data, Map<String, String> extendMap, Class clazz,
                                    boolean isWriteHeader, String targetPath) throws Exception {

        exportObjects2Excel(templatePath, 0, data, extendMap, clazz, isWriteHeader, targetPath);
    }

    public void exportObjects2Excel(String templatePath, List<?> data, Map<String, String> extendMap, Class clazz,
                                    boolean isWriteHeader, OutputStream os) throws Exception {

        exportObjects2Excel(templatePath, 0, data, extendMap, clazz, isWriteHeader, os);
    }

    public void exportObjects2Excel(String templatePath, List<?> data, Map<String, String> extendMap, Class clazz,
                                    String targetPath) throws Exception {

        exportObjects2Excel(templatePath, 0, data, extendMap, clazz, false, targetPath);
    }

    public void exportObjects2Excel(String templatePath, List<?> data, Map<String, String> extendMap, Class clazz,
                                    OutputStream os) throws Exception {

        exportObjects2Excel(templatePath, 0, data, extendMap, clazz, false, os);
    }

    public void exportObjects2Excel(String templatePath, List<?> data, Class clazz, String targetPath)
            throws Exception {

        exportObjects2Excel(templatePath, 0, data, null, clazz, false, targetPath);
    }

    public void exportObjects2Excel(String templatePath, List<?> data, Class clazz, OutputStream os)
            throws Exception {

        exportObjects2Excel(templatePath, 0, data, null, clazz, false, os);
    }

    private ExcelTemplate exportExcelByModuleHandler(String templatePath, int sheetIndex, List<?> data,
                                                     Map<String, String> extendMap, Class clazz, boolean isWriteHeader)
            throws Exception {

        ExcelTemplate templates = ExcelTemplate.getInstance(templatePath, sheetIndex);
        templates.extendData(extendMap);
        List<ExcelHeader> headers = Utils.getHeaderList(clazz);
        if (isWriteHeader) {
            // 写标题
            templates.createNewRow();
            for (ExcelHeader header : headers) {
                templates.createCell(header.getTitle(), null);
            }
        }

        for (Object object : data) {
            templates.createNewRow();
            templates.insertSerial(null);
            for (ExcelHeader header : headers) {
                templates.createCell(BeanUtils.getProperty(object, header.getFiled()), null);
            }
        }
        return templates;
    }

}
